import { Cell } from '@antv/x6';
import { SetterOrUpdater } from 'recoil';

import { BaseNodeProps, NodeDataTypes } from '@/components/complex/BaseNode/define';
import { useGraph } from '@/hooks/useGraph';
import { findParentVariables } from '@/utils/graph';

export const activeNodeIdAtom = atom<string | null>({
  default: '',
  key: 'activeNodeId'
});

const cellDataAtom = atom<BaseNodeProps<any>>({
  default: {},
  key: 'cellData'
});

export const useCurrentNode = <NT extends keyof NodeDataTypes>() => {
  const { graph, saveGraph } = useGraph();
  const [activeNodeId, setActiveNodeId] = useRecoilState(activeNodeIdAtom);
  const [cellData, setCellData] = useRecoilState(cellDataAtom) as [BaseNodeProps<NT>, SetterOrUpdater<BaseNodeProps<NT>>];
  const privateVariables = cellData.privateVariables || [];
  const publicVariables = cellData.publicVariables || [];
  const getParentPrivateVariables = () => findParentVariables(graph!, activeNodeId!, 'private');
  const getParentPublicVariables = () => findParentVariables(graph!, activeNodeId!, 'public');
  const currentAndParentPrivateVariables = privateVariables.concat(getParentPrivateVariables());
  const currentAndParentPublicVariables = publicVariables.concat(getParentPublicVariables());

  const getNodeDataFor = useCallback(() => {
    return cellData.data;
  }, [cellData]);

  const setNodeData = useCallback(
    (data: BaseNodeProps<NT>, options?: Cell.SetDataOptions) => {
      const cellData = graph?.getCellById(activeNodeId!).getData();
      const nodeData = {
        ...cellData,
        ...data
      };
      graph?.getCellById(activeNodeId!).setData(nodeData, { overwrite: true, ...options });
      setCellData(nodeData);
      saveGraph();
    },
    [activeNodeId, graph, saveGraph, setCellData]
  );

  const setNodeDataFor = useCallback(
    (data: NodeDataTypes[NT], options?: Cell.SetDataOptions) => {
      setNodeData(
        {
          data
        },
        options
      );
    },
    [setNodeData]
  );

  const setPrivateVariables = useCallback(
    (privateVariables: VariableItem[]) => {
      setNodeData({
        privateVariables
      });
      saveGraph();
    },
    [saveGraph, setNodeData]
  );

  const setPublicVariables = useCallback(
    (publicVariables: VariableItem[]) => {
      setNodeData({
        publicVariables: publicVariables.length === 0 ? [] : publicVariables
      });
      saveGraph();
    },
    [saveGraph, setNodeData]
  );

  const variable2Options = useCallback((variables: VariableItem[]) => {
    return variables.map((item) => {
      return {
        label: item.varLabel,
        value: item.varName,
        varType: item.varType!
      };
    });
  }, []);

  useEffect(() => {
    if (activeNodeId && graph) {
      const data = graph.getCellById(activeNodeId).getData() || {};
      setCellData(data);
    }
  }, [activeNodeId, graph, setCellData]);

  return {
    setNodeData,
    activeNodeId,
    getNodeDataFor,
    setNodeDataFor,
    setActiveNodeId,
    setPublicVariables,
    setPrivateVariables,
    publicVariables,
    privateVariables,
    variable2Options,
    currentNodeData: cellData,
    getParentPrivateVariables,
    /** 当前节点及父节点的公共变量 */
    currentAndParentPublicVariables,
    /** 当前节点及父节点的私有变量 */
    currentAndParentPrivateVariables
  };
};
